
#include <atomic>
#include <unordered_set>

#include "tinyrpc/base/coroutine/coroutineStatus.h"
#include "coroutine_sync.h"
#include <iostream>
namespace TinyRPC{




// void CoWakeUp(CoroutinePtr co){
//     co->setStatus(CoroutineStatus::READY);
//     EventLoop::CurrentEventLoop()->queueInLoop(Task(co));
// }


void CoLock::unlock(){
    int old_val;
    while (true){
        // 解锁成功
        
        if((old_val = m_val) == LOCKED && m_val.compare_exchange_strong(old_val, UNLOCKED)){
            while(!m_waitList.empty()){
                EventLoopAndCoroutine ec;
                {
                    LockGuard<SpinLock> guard(m_spinLock);
                    ec = m_waitList.front();
                    m_waitList.pop_front();
                }
                
                ec.eventloop->queueInLoop(ec.coroutine);
            }
            break;
        }
        
        
    }
}

void CoLock::lock(){
    int old_val;
    while(true){
       
        // 没有加锁成功
        if( //(m_next != nullptr && m_next.get()!=Coroutine::CurrentCoroutine().get()) ||           // 已经有next了
            (old_val = m_val) != UNLOCKED || !m_val.compare_exchange_strong(old_val, LOCKED))      // 没有加锁成功
        {
            // if(m_next == nullptr){
            //     m_next =  Coroutine::CurrentCoroutine();
            // }
            Coroutine::CurrentCoroutine()->setStatus(CoroutineStatus::BLOCKED);
            {
                LockGuard<SpinLock> guard(m_spinLock);
                m_waitList.push_back(EventLoopAndCoroutine(EventLoop::CurrentEventLoop(), Coroutine::CurrentCoroutine()));
            }
            Coroutine::Block();
        }else{                                 // 加锁成功
            //m_next = nullptr;                  // 将next设置为空， 这样别的协程就可以设置next了
            break;
        }
    }
    
}




void CoSem::post(){
    int old_val;
    while (true)
    {
       
        // 解锁成功
        if((old_val = m_val)>0 && m_val.compare_exchange_strong(old_val, old_val+1)){
            while(!m_waitList.empty()){
                EventLoopAndCoroutine ec;
                {
                    LockGuard<SpinLock> guard(m_spinLock);
                    ec = m_waitList.front();
                    m_waitList.pop_front();
                }
                
                ec.eventloop->queueInLoop(ec.coroutine);
            }
            break;
        }
        
        
    }
}
void CoSem::wait(){
    int old_val;

    while (true)
    {
        if((old_val = m_val) <= 0 || !m_val.compare_exchange_strong(old_val, old_val-1)){
            
            Coroutine::CurrentCoroutine()->setStatus(CoroutineStatus::BLOCKED);
            {
                LockGuard<SpinLock> guard(m_spinLock);
                m_waitList.push_back(EventLoopAndCoroutine(EventLoop::CurrentEventLoop(), Coroutine::CurrentCoroutine()));
            }
            Coroutine::Block();
        }else{
            break;
        }
    }
    
   
}

}